﻿using SuperSocket.ClientEngine;
using SuperSocket.ClientEngine.Protocol;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using TransferClientLib.UpLoad.Command;
using TransferCommon;
namespace TransferClientLib.UpLoad
{
    public class UpLoadEngine : IDisposable
    {

        protected IClientCommandReader<TransferCommandInfo> CommandReader { get; private set; }

        public delegate bool FileExistEventHandler(EventArgs e);

        public delegate void TransferCompleteEventHandler(EventArgs e);

        public delegate void TransferErrorEventHandler(TransferErrorEventArgs e);

        public delegate void TransferStepEventHandler(TransferStepEventArgs e);
        private string _fileName;
        private string _saveName;
        private TcpClientSession Client;
        private Dictionary<string, ICommand<UpLoadEngine, TransferCommandInfo>> m_CommandDict = new Dictionary<string, ICommand<UpLoadEngine, TransferCommandInfo>>(StringComparer.OrdinalIgnoreCase);
        private FileStream m_fileStream;
        private AutoResetEvent m_OpenedEvent = new AutoResetEvent(false);
        private AutoResetEvent m_EndEvent = new AutoResetEvent(false);
        private int PacketSize = 1024 * 30;
        private byte[] readBuffer;
        private long TransferedLength = 0L;
        private int TransferStatus = 0;
        //0:初始化状态，1：CheckExist,3,OnUpLoad,开始上传，4，OnDoData，数据传输中，5，数据传输完成,6,已结束的标志
        private long TransferTotalLength = 0L;

        public event FileExistEventHandler FileExist;

        public event TransferCompleteEventHandler TransferComplete;

        public event TransferErrorEventHandler TransferError;

        public event TransferStepEventHandler TransferStep;

        public void BeginUpLoad()
        {
            try
            {
                if (this.TransferStatus != 0)
                {
                    throw new Exception("状态错误");
                }
                this.Client.Connect();
                if (!this.m_OpenedEvent.WaitOne(5000))
                {
                    throw new Exception("连接失败");
                }
                this.SendMessage(UpLoadOP.CheckExist, this._saveName);
            }
            catch (Exception exception)
            {
                this.OnTransferError(new TransferErrorEventArgs(exception));
            }
        }

        private void client_Closed(object sender, EventArgs e)
        {
        }

        private void client_Connected(object sender, EventArgs e)
        {
            this.m_OpenedEvent.Set();
        }

        private void client_DataReceived(object sender, DataEventArgs e)
        {
            this.m_OnDataReceived(e.Data, e.Offset, e.Length);
        }

        private void client_Error(object sender, SuperSocket.ClientEngine.ErrorEventArgs e)
        {
        }

        public void Dispose()
        {
            this._fileName = string.Empty;
            this._saveName = string.Empty;
            if (this.m_fileStream != null)
            {
                this.m_fileStream.Close();
                this.m_fileStream = null;
            }
            TcpClientSession client = this.Client;
            if (client != null)
            {
                client.Error -= new EventHandler<SuperSocket.ClientEngine.ErrorEventArgs>(this.client_Error);
                client.DataReceived -= new EventHandler<DataEventArgs>(this.client_DataReceived);
                client.Connected -= new EventHandler(this.client_Connected);
                client.Closed -= new EventHandler(this.client_Closed);
                if (client.IsConnected)
                {
                    client.Close();
                }
                this.Client = null;
            }
            //this.TransferStatus = 0;
            this.TransferedLength = 0L;
            this.TransferTotalLength = 0L;
            this.readBuffer = null;
            this.CommandReader = null;
            this.m_CommandDict.Clear();
            this.m_OpenedEvent.Reset();
            this.m_EndEvent.Reset();
        }

        internal void DoData()
        {
            this.TransferStatus = 4;
            while (this.TransferedLength < this.TransferTotalLength)
            {
                int length = this.m_fileStream.Read(this.readBuffer, 0, this.PacketSize);
                this.SendData(UpLoadOP.DoData, this.readBuffer, 0, length);
                this.TransferedLength += length;
                this.OnTransferStep(this.TransferTotalLength, this.TransferedLength, length);
            }
            this.TransferStatus = 5;
            this.SendData(UpLoadOP.DoEnd, new byte[] { 1 }, 0, 1);
            DoEnd();
        }
        internal void DoEnd()
        {
            this.TransferStatus = 6;
            this.Dispose();
            if (this.TransferComplete != null)
            {
                this.TransferComplete(new EventArgs());
            }
        }

        //客户端自己触发结束事件
        //internal void OnDoEnd()
        //{
        //    DoEnd();
        //}


        internal void DoUpLoad()
        {
            this.m_fileStream = new FileStream(this._fileName, FileMode.Open, FileAccess.Read);
            this.TransferTotalLength = this.m_fileStream.Length;
            UpLoadInfo t = new UpLoadInfo(this._fileName, this.m_fileStream.Length);
            byte[] data = SerializeHelp.Serialize<UpLoadInfo>(t);
            this.SendData(UpLoadOP.DoUpLoad, data, 0, data.Length);
        }

        private void ExecuteCommand(TransferCommandInfo commandInfo)
        {
            ICommand<UpLoadEngine, TransferCommandInfo> command;
            if (this.m_CommandDict.TryGetValue(commandInfo.Key, out command))
            {
                command.ExecuteCommand(this, commandInfo);
            }
        }

        public void Init(EndPoint endpoint, string fileName, string saveName)
        {
            string str = ConfigurationManager.AppSettings["PacketSize"];
            if (!string.IsNullOrWhiteSpace(str))
            {
                this.PacketSize = Convert.ToInt32(str);
            }
            this.readBuffer = new byte[this.PacketSize];
            this._fileName = fileName;
            this._saveName = saveName;
            UpLoadCommandBase[] baseArray = new UpLoadCommandBase[] { new CheckExist(), new TransferClientLib.UpLoad.Command.DoData(), new TransferClientLib.UpLoad.Command.DoEnd() };
            foreach (UpLoadCommandBase base2 in baseArray)
            {
                this.m_CommandDict.Add(base2.Name, base2);
            }
            TcpClientSession session = new AsyncTcpSession(endpoint);
            session.Error += new EventHandler<SuperSocket.ClientEngine.ErrorEventArgs>(this.client_Error);
            session.DataReceived += new EventHandler<DataEventArgs>(this.client_DataReceived);
            session.Connected += new EventHandler(this.client_Connected);
            session.Closed += new EventHandler(this.client_Closed);
            this.Client = session;
            this.CommandReader = new UpLoadReader(this);
        }

        private void m_OnDataReceived(byte[] data, int offset, int length)
        {
            while (true)
            {
                if (this.CommandReader == null)
                    return;
                int num;
                TransferCommandInfo commandInfo = this.CommandReader.GetCommandInfo(data, offset, length, out num);
                if (this.CommandReader.NextCommandReader != null)
                {
                    this.CommandReader = this.CommandReader.NextCommandReader;
                }
                if (commandInfo != null)
                {
                    this.ExecuteCommand(commandInfo);
                }
                if (num <= 0)
                {
                    return;
                }
                offset = (offset + length) - num;
                length = num;
            }
        }

        internal bool OnFileExist()
        {
            if (this.FileExist != null)
            {
                return this.FileExist(new EventArgs());
            }
            this.OnTransferError(new TransferErrorEventArgs(new Exception("存在相同文件")));
            return false;
        }

        private void OnTransferError(TransferErrorEventArgs e)
        {
            if (this.TransferError != null)
            {
                this.TransferError(e);
            }
            this.Dispose();
        }

        internal void OnTransferStep(long _TotalLen, long _TransferLen, int _CurrentPacket)
        {
            if (this.TransferStep != null)
            {
                this.TransferStep(new TransferStepEventArgs(_TotalLen, _TransferLen, _CurrentPacket));
            }
        }

        private void SendData(UpLoadOP opCode, byte[] data, int offset, int length)
        {
            byte[] senddata = new byte[length + 5];
            senddata[0] = 0;
            senddata[1] = (byte)((int)opCode / 256);
            senddata[2] = (byte)((int)opCode % 256);
            senddata[3] = (byte)(length / 256);
            senddata[4] = (byte)(length % 256);
            Buffer.BlockCopy(data, offset, senddata, 5, length);
            this.Client.Send(senddata, 0, senddata.Length);
        }

        private void SendMessage(UpLoadOP opCode, string msg)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(msg);
            this.SendData(opCode, bytes, 0, bytes.Length);
        }
    }
}
